home *** CD-ROM | disk | FTP | other *** search
/ HyperLib 1997 Winter - Disc 1 / HYPERLIB-1997-Winter-CD1.ISO.7z / HYPERLIB-1997-Winter-CD1.ISO / オンラインウェア / PRG / PowerLisp 2.01 FAT Folder.sit / PowerLisp 2.01 FAT Folder / PowerLisp 2.01 ƒ / Library / clos.lisp < prev    next >
Lisp/Scheme  |  1996-05-17  |  63KB  |  1,659 lines

  1. ;;;-*-Mode:LISP; Package: (CLOSETTE :USE LISP); Base:10; Syntax:Common-lisp -*-
  2. ;;;
  3. ;;;    Minor modifications for use with PowerLisp 2.0  (May 15, 1996)
  4. ;;;
  5. ;;; Closette Version 1.0 (February 10, 1991)
  6. ;;;
  7. ;;; Minor revisions of September 27, 1991 by desRivieres@parc.xerox.com:
  8. ;;;   - remove spurious "&key" in header of initialize-instance method
  9. ;;;     for standard-class (bottom of pg.310 of AMOP)
  10. ;;;   - add recommendation about not compiling this file 
  11. ;;;   - change comment to reflect PARC ftp server name change  
  12. ;;;   - add a BOA constructor to std-instance to please AKCL
  13. ;;;   - by default, efunctuate methods rather than compile them
  14. ;;;   - also make minor changes to newcl.lisp
  15. ;;;
  16. ;;; Copyright (c) 1990, 1991 Xerox Corporation.
  17. ;;; All rights reserved.
  18. ;;;
  19. ;;; Use and copying of this software and preparation of derivative works
  20. ;;; based upon this software are permitted.  Any distribution of this
  21. ;;; software or derivative works must comply with all applicable United
  22. ;;; States export control laws.
  23. ;;; 
  24. ;;; This software is made available AS IS, and Xerox Corporation makes no
  25. ;;; warranty about the software, its performance or its conformity to any
  26. ;;; specification.
  27. ;;; 
  28. ;;;
  29. ;;; Closette is an implementation of a subset of CLOS with a metaobject
  30. ;;; protocol as described in "The Art of The Metaobject Protocol",
  31. ;;; MIT Press, 1991.
  32. ;;;
  33. ;;; This program is available by anonymous FTP, from the /pub/pcl/mop
  34. ;;; directory on parcftp.xerox.com.
  35.  
  36. ;;; This is the file closette.lisp
  37.  
  38. ;;; N.B. Load this source file directly, rather than trying to compile it.
  39.  
  40. ;;(in-package 'closette :use '(lisp))
  41. (provide :clos)
  42. (in-package 'common-lisp)
  43.  
  44. ;;; When running in a Common Lisp that doesn't yet support function names like
  45. ;;; (setf foo), you should first load the file newcl.lisp.  This next little
  46. ;;; bit imports stuff from there as needed.
  47.  
  48. #|        ;; RGC
  49. #-Genera
  50. (import '(newcl:print-unreadable-object))
  51.  
  52. #-Genera
  53. (shadowing-import '(newcl:defun newcl:fboundp newcl:fmakunbound
  54.                     newcl:fdefinition))
  55.  
  56. #-Genera
  57. (export '(newcl:defun newcl:fboundp newcl:fmakunbound newcl:fdefinition))
  58.  
  59. #+Genera
  60. (shadowing-import '(future-common-lisp:setf
  61.                     future-common-lisp:fboundp
  62.                     future-common-lisp:fmakunbound
  63.                     future-common-lisp:fdefinition
  64.                     future-common-lisp:print-unreadable-object))
  65.  
  66. #+Genera
  67. (export '(future-common-lisp:setf
  68.           future-common-lisp:fboundp
  69.           future-common-lisp:fmakunbound
  70.           future-common-lisp:fdefinition
  71.           future-common-lisp:print-unreadable-object))
  72. |#         ;; RGC
  73.  
  74. (defvar exports
  75.         '(defclass defgeneric defmethod
  76.           find-class class-of
  77.           call-next-method next-method-p
  78.           slot-value slot-boundp slot-exists-p slot-makunbound
  79.           make-instance change-class
  80.           initialize-instance reinitialize-instance shared-initialize
  81.           update-instance-for-different-class
  82.           print-object
  83.  
  84.           standard-object
  85.           standard-class standard-generic-function standard-method
  86.           class-name
  87.  
  88.           class-direct-superclasses class-direct-slots
  89.           class-precedence-list class-slots class-direct-subclasses
  90.           class-direct-methods
  91.           generic-function-name generic-function-lambda-list 
  92.           generic-function-methods generic-function-discriminating-function
  93.           generic-function-method-class
  94.           method-lambda-list method-qualifiers method-specializers method-body
  95.           method-environment method-generic-function method-function
  96.           slot-definition-name slot-definition-initfunction 
  97.           slot-definition-initform slot-definition-initargs
  98.           slot-definition-readers slot-definition-writers
  99.           slot-definition-allocation
  100.           ;;
  101.           ;; Class-related metaobject protocol
  102.           ;; 
  103.           compute-class-precedence-list compute-slots
  104.           compute-effective-slot-definition
  105.           finalize-inheritance allocate-instance
  106.           slot-value-using-class slot-boundp-using-class 
  107.           slot-exists-p-using-class slot-makunbound-using-class
  108.           ;;
  109.           ;; Generic function related metaobject protocol
  110.           ;;
  111.           compute-discriminating-function
  112.           compute-applicable-methods-using-classes method-more-specific-p
  113.           compute-effective-method-function compute-method-function
  114.           apply-methods apply-method
  115.           describe-object
  116.           find-generic-function  ; Necessary artifact of this implementation
  117.           ))
  118.  
  119.  
  120. (export exports)
  121.  
  122. ;;;
  123. ;;; Utilities 
  124. ;;;
  125.  
  126. ;;; push-on-end is like push except it uses the other end:
  127.  
  128. (defmacro push-on-end (value location)
  129.   `(setf ,location (nconc ,location (list ,value))))
  130.  
  131. ;;; (setf getf*) is like (setf getf) except that it always changes the list,
  132. ;;;              which must be non-nil.
  133.  
  134. (defun (setf getf*) (new-value plist key)
  135.   (block body
  136.     (do ((x plist (cddr x)))
  137.       ((null x))
  138.       (when (eq (car x) key)
  139.         (setf (car (cdr x)) new-value)
  140.         (return-from body new-value)))
  141.     (push-on-end key plist)
  142.     (push-on-end new-value plist)
  143.     new-value))
  144.  
  145. ;;; mapappend is like mapcar except that the results are appended together:
  146.  
  147. (defun mapappend (fun &rest args)
  148.   (if (some #'null args)
  149.       ()
  150.       (append (apply fun (mapcar #'car args))
  151.               (apply #'mapappend fun (mapcar #'cdr args)))))
  152.  
  153. ;;; mapplist is mapcar for property lists:
  154.  
  155. (defun mapplist (fun x)
  156.   (if (null x)
  157.       ()
  158.       (cons (funcall fun (car x) (cadr x))
  159.             (mapplist fun (cddr x)))))
  160.  
  161. ;;;
  162. ;;; Standard instances
  163. ;;;
  164.  
  165. ;;; This implementation uses structures for instances, because they're the only
  166. ;;; kind of Lisp object that can be easily made to print whatever way we want.
  167.  
  168.  
  169. (defstruct (std-instance (:constructor allocate-std-instance (class slots))
  170.                    #+kcl (:constructor make-std-instance-for-sharp-s)
  171.                          (:predicate std-instance-p)
  172.                          (:print-function print-std-instance))
  173.   class
  174.   slots)
  175.  
  176. (defun print-std-instance (instance stream depth)
  177.   (declare (ignore depth))
  178.   (print-object instance stream))
  179.  
  180. ;;; Standard instance allocation
  181.  
  182. (defparameter secret-unbound-value (list "slot unbound"))
  183.  
  184. (defun instance-slot-p (slot)
  185.   (eq (slot-definition-allocation slot) ':instance))
  186.  
  187. (defun std-allocate-instance (class)
  188.   (allocate-std-instance
  189.     class
  190.     (allocate-slot-storage (count-if #'instance-slot-p (class-slots class))
  191.                            secret-unbound-value)))
  192.  
  193. ;;; Simple vectors are used for slot storage.
  194.  
  195. (defun allocate-slot-storage (size initial-value)
  196.   (make-array size :initial-element initial-value))
  197.  
  198. ;;; Standard instance slot access
  199.  
  200. ;;; N.B. The location of the effective-slots slots in the class metaobject for
  201. ;;; standard-class must be determined without making any further slot
  202. ;;; references.
  203.  
  204. (defvar the-slots-of-standard-class) ;standard-class's class-slots
  205. (defvar the-class-standard-class)    ;standard-class's class metaobject
  206.  
  207. (defun slot-location (class slot-name)
  208.   (if (and (eq slot-name 'effective-slots)
  209.            (eq class the-class-standard-class))
  210.       (position 'effective-slots the-slots-of-standard-class
  211.                :key #'slot-definition-name)
  212.       (let ((slot (find slot-name
  213.                         (class-slots class)
  214.                         :key #'slot-definition-name)))
  215.         (if (null slot)
  216.             (error "The slot ~S is missing from the class ~S."
  217.                    slot-name class)
  218.             (let ((pos (position slot
  219.                                  (remove-if-not #'instance-slot-p
  220.                                                 (class-slots class)))))
  221.                (if (null pos)
  222.                    (error "The slot ~S is not an instance~@
  223.                            slot in the class ~S."
  224.                           slot-name class)
  225.                    pos))))))
  226.  
  227. (defun slot-contents (slots location)
  228.   (svref slots location))
  229.  
  230. (defun (setf slot-contents) (new-value slots location)
  231.   (setf (svref slots location) new-value))
  232.  
  233. (defun std-slot-value (instance slot-name)
  234.   (let* ((location (slot-location (class-of instance) slot-name))
  235.          (slots (std-instance-slots instance))
  236.          (val (slot-contents slots location)))
  237.     (if (eq secret-unbound-value val)
  238.         (error "The slot ~S is unbound in the object ~S."
  239.                slot-name instance)
  240.         val)))
  241. (defun slot-value (object slot-name)
  242.   (if (eq (class-of (class-of object)) the-class-standard-class)
  243.       (std-slot-value object slot-name)
  244.       (slot-value-using-class (class-of object) object slot-name)))
  245.  
  246. (defun (setf std-slot-value) (new-value instance slot-name)
  247.   (let ((location (slot-location (class-of instance) slot-name))
  248.         (slots (std-instance-slots instance)))
  249.     (setf (slot-contents slots location) new-value)))
  250. (defun (setf slot-value) (new-value object slot-name)
  251.   (if (eq (class-of (class-of object)) the-class-standard-class)
  252.       (setf (std-slot-value object slot-name) new-value)
  253.       (setf-slot-value-using-class 
  254.         new-value (class-of object) object slot-name)))
  255.  
  256. (defun std-slot-boundp (instance slot-name)
  257.   (let ((location (slot-location (class-of instance) slot-name))
  258.         (slots (std-instance-slots instance)))
  259.     (not (eq secret-unbound-value (slot-contents slots location)))))
  260. (defun slot-boundp (object slot-name)
  261.   (if (eq (class-of (class-of object)) the-class-standard-class)
  262.       (std-slot-boundp object slot-name)
  263.       (slot-boundp-using-class (class-of object) object slot-name)))
  264.  
  265. (defun std-slot-makunbound (instance slot-name)
  266.   (let ((location (slot-location (class-of instance) slot-name))
  267.         (slots (std-instance-slots instance)))
  268.     (setf (slot-contents slots location) secret-unbound-value))
  269.   instance)
  270. (defun slot-makunbound (object slot-name)
  271.   (if (eq (class-of (class-of object)) the-class-standard-class)
  272.       (std-slot-makunbound object slot-name)
  273.       (slot-makunbound-using-class (class-of object) object slot-name)))
  274.  
  275. (defun std-slot-exists-p (instance slot-name)
  276.   (not (null (find slot-name (class-slots (class-of instance))
  277.                    :key #'slot-definition-name))))
  278. (defun slot-exists-p (object slot-name)
  279.   (if (eq (class-of (class-of object)) the-class-standard-class)
  280.       (std-slot-exists-p object slot-name)
  281.       (slot-exists-p-using-class (class-of object) object slot-name)))
  282.  
  283. ;;; class-of
  284.  
  285. (defun class-of (x)
  286.   (if (std-instance-p x)
  287.       (std-instance-class x)
  288.       (built-in-class-of x)))
  289.  
  290. ;;; N.B. This version of built-in-class-of is straightforward but very slow.
  291.  
  292. (defun built-in-class-of (x)
  293.   (typecase x
  294.     (null                                          (find-class 'null))
  295.     ((and symbol (not null))                       (find-class 'symbol))
  296.     ((complex *)                                   (find-class 'complex))
  297.     ((integer * *)                                 (find-class 'integer))
  298.     ((float * *)                                   (find-class 'float))
  299.     (cons                                          (find-class 'cons))
  300.     (character                                     (find-class 'character))
  301.     (hash-table                                    (find-class 'hash-table))
  302.     (package                                       (find-class 'package))
  303.     (pathname                                      (find-class 'pathname))
  304.     (readtable                                     (find-class 'readtable))
  305.     (stream                                        (find-class 'stream))
  306.     ((and number (not (or integer complex float))) (find-class 'number))
  307.     ((string *)                                    (find-class 'string))
  308.     ((bit-vector *)                                (find-class 'bit-vector))
  309.     ((and (vector * *) (not (or string vector)))   (find-class 'vector))
  310.     ((and (array * *) (not vector))                (find-class 'array))
  311.     ((and sequence (not (or vector list)))         (find-class 'sequence))
  312.     (function                                      (find-class 'function))
  313.     (t                                             (find-class 't))))
  314.  
  315. ;;; subclassp and sub-specializer-p
  316.  
  317. (defun subclassp (c1 c2)
  318.   (not (null (find c2 (class-precedence-list c1)))))
  319.  
  320. (defun sub-specializer-p (c1 c2 c-arg)
  321.   (let ((cpl (class-precedence-list c-arg)))
  322.     (not (null (find c2 (cdr (member c1 cpl)))))))
  323.  
  324. ;;;
  325. ;;; Class metaobjects and standard-class
  326. ;;;
  327.  
  328. (defparameter the-defclass-standard-class  ;standard-class's defclass form
  329.  '(defclass standard-class ()
  330.       ((name :initarg :name)              ; :accessor class-name
  331.        (direct-superclasses               ; :accessor class-direct-superclasses
  332.         :initarg :direct-superclasses) 
  333.        (direct-slots)                     ; :accessor class-direct-slots
  334.        (class-precedence-list)            ; :accessor class-precedence-list
  335.        (effective-slots)                  ; :accessor class-slots
  336.        (direct-subclasses :initform ())   ; :accessor class-direct-subclasses
  337.        (direct-methods :initform ()))))   ; :accessor class-direct-methods
  338.  
  339. ;;; Defining the metaobject slot accessor function as regular functions 
  340. ;;; greatly simplifies the implementation without removing functionality.
  341.  
  342. (defun class-name (class) (std-slot-value class 'name))
  343. (defun (setf class-name) (new-value class)
  344.   (setf (slot-value class 'name) new-value))
  345.  
  346. (defun class-direct-superclasses (class)
  347.   (slot-value class 'direct-superclasses))
  348. (defun (setf class-direct-superclasses) (new-value class)
  349.   (setf (slot-value class 'direct-superclasses) new-value))
  350.  
  351. (defun class-direct-slots (class)
  352.   (slot-value class 'direct-slots))
  353. (defun (setf class-direct-slots) (new-value class)
  354.   (setf (slot-value class 'direct-slots) new-value))
  355.  
  356. (defun class-precedence-list (class)
  357.   (slot-value class 'class-precedence-list))
  358. (defun (setf class-precedence-list) (new-value class)
  359.   (setf (slot-value class 'class-precedence-list) new-value))
  360.  
  361. (defun class-slots (class)
  362.   (slot-value class 'effective-slots))
  363. (defun (setf class-slots) (new-value class)
  364.   (setf (slot-value class 'effective-slots) new-value))
  365.  
  366. (defun class-direct-subclasses (class)
  367.   (slot-value class 'direct-subclasses))
  368. (defun (setf class-direct-subclasses) (new-value class)
  369.   (setf (slot-value class 'direct-subclasses) new-value))
  370.  
  371. (defun class-direct-methods (class)
  372.   (slot-value class 'direct-methods))
  373. (defun (setf class-direct-methods) (new-value class)
  374.   (setf (slot-value class 'direct-methods) new-value))
  375.  
  376. ;;; defclass
  377.  
  378. (defmacro defclass (name direct-superclasses direct-slots
  379.                     &rest options)
  380.   `(ensure-class ',name
  381.      :direct-superclasses
  382.        ,(canonicalize-direct-superclasses direct-superclasses)
  383.      :direct-slots
  384.        ,(canonicalize-direct-slots direct-slots)
  385.      ,@(canonicalize-defclass-options options)))
  386.  
  387. (defun canonicalize-direct-slots (direct-slots)
  388.    `(list ,@(mapcar #'canonicalize-direct-slot direct-slots)))
  389.  
  390. (defun canonicalize-direct-slot (spec)
  391.   (if (symbolp spec)
  392.       `(list :name ',spec)
  393.       (let ((name (car spec))
  394.             (initfunction nil)
  395.             (initform nil)
  396.             (initargs ())
  397.             (readers ())
  398.             (writers ())
  399.             (other-options ()))
  400.         (do ((olist (cdr spec) (cddr olist)))
  401.             ((null olist))
  402.           (case (car olist)
  403.             (:initform
  404.              (setq initfunction
  405.                    `(function (lambda () ,(cadr olist))))
  406.              (setq initform `',(cadr olist)))
  407.             (:initarg 
  408.              (push-on-end (cadr olist) initargs))
  409.             (:reader 
  410.              (push-on-end (cadr olist) readers))
  411.             (:writer 
  412.              (push-on-end (cadr olist) writers))
  413.             (:accessor
  414.              (push-on-end (cadr olist) readers)
  415.              (push-on-end `(setf ,(cadr olist)) writers))
  416.             (otherwise 
  417.              (push-on-end `',(car olist) other-options)
  418.              (push-on-end `',(cadr olist) other-options))))
  419.         `(list
  420.            :name ',name
  421.            ,@(when initfunction
  422.                `(:initform ,initform
  423.                  :initfunction ,initfunction))
  424.            ,@(when initargs `(:initargs ',initargs))
  425.            ,@(when readers `(:readers ',readers))
  426.            ,@(when writers `(:writers ',writers))
  427.            ,@other-options))))
  428.  
  429. (defun canonicalize-direct-superclasses (direct-superclasses)
  430.   `(list ,@(mapcar #'canonicalize-direct-superclass direct-superclasses)))
  431.  
  432. (defun canonicalize-direct-superclass (class-name)
  433.   `(find-class ',class-name))
  434.  
  435. (defun canonicalize-defclass-options (options)
  436.   (mapappend #'canonicalize-defclass-option options))
  437.  
  438. (defun canonicalize-defclass-option (option)
  439.   (case (car option)
  440.     (:metaclass
  441.       (list ':metaclass
  442.        `(find-class ',(cadr option))))
  443.     (:default-initargs
  444.       (list 
  445.        ':direct-default-initargs
  446.        `(list ,@(mapappend
  447.                   #'(lambda (x) x)
  448.                   (mapplist
  449.                     #'(lambda (key value)
  450.                         `(',key ,value))
  451.                     (cdr option))))))
  452.     (t (list `',(car option) `',(cadr option)))))
  453.  
  454. ;;; find-class
  455.  
  456. (let ((class-table (make-hash-table :test #'eq)))
  457.  
  458.   (defun find-class (symbol &optional (errorp t))
  459.     (let ((class (gethash symbol class-table nil)))
  460.       (if (and (null class) errorp)
  461.           (error "No class named ~S." symbol)
  462.           class)))
  463.  
  464.   (defun (setf find-class) (new-value symbol)
  465.     (setf (gethash symbol class-table) new-value))
  466.  
  467.   (defun forget-all-classes ()
  468.     (clrhash class-table)
  469.     (values))
  470.  ) ;end let class-table
  471.  
  472. ;;; Ensure class
  473.  
  474. (defun ensure-class (name &rest all-keys
  475.                           &key (metaclass the-class-standard-class)
  476.                           &allow-other-keys)
  477.   (if (find-class name nil)
  478.       (error "Can't redefine the class named ~S." name)
  479.       (let ((class (apply (if (eq metaclass the-class-standard-class)
  480.                               #'make-instance-standard-class
  481.                               #'make-instance)
  482.                           metaclass :name name all-keys)))
  483.         (setf (find-class name) class)
  484.         class)))
  485.  
  486. ;;; make-instance-standard-class creates and initializes an instance of
  487. ;;; standard-class without falling into method lookup.  However, it cannot be
  488. ;;; called until standard-class itself exists.
  489.  
  490. (defun make-instance-standard-class 
  491.        (metaclass &key name direct-superclasses direct-slots
  492.                   &allow-other-keys)
  493.   (declare (ignore metaclass))
  494.   (let ((class (std-allocate-instance the-class-standard-class)))
  495.     (setf (class-name class) name)
  496.     (setf (class-direct-subclasses class) ())
  497.     (setf (class-direct-methods class) ())
  498.     (std-after-initialization-for-classes class
  499.        :direct-slots direct-slots
  500.        :direct-superclasses direct-superclasses)
  501.     class))
  502.  
  503. (defun std-after-initialization-for-classes
  504.        (class &key direct-superclasses direct-slots &allow-other-keys)
  505.   (let ((supers
  506.           (or direct-superclasses
  507.               (list (find-class 'standard-object)))))
  508.     (setf (class-direct-superclasses class) supers)
  509.     (dolist (superclass supers)
  510.       (push class (class-direct-subclasses superclass))))
  511.   (let ((slots 
  512.           (mapcar #'(lambda (slot-properties)
  513.                       (apply #'make-direct-slot-definition
  514.                              slot-properties))
  515.                     direct-slots)))
  516.     (setf (class-direct-slots class) slots)
  517.     (dolist (direct-slot slots)
  518.       (dolist (reader (slot-definition-readers direct-slot))
  519.         (add-reader-method 
  520.           class reader (slot-definition-name direct-slot)))
  521.       (dolist (writer (slot-definition-writers direct-slot))
  522.         (add-writer-method 
  523.           class writer (slot-definition-name direct-slot)))))
  524.   (funcall (if (eq (class-of class) the-class-standard-class)
  525.               #'std-finalize-inheritance
  526.               #'finalize-inheritance)
  527.            class)
  528.   (values))
  529.  
  530. ;;; Slot definition metaobjects
  531.  
  532. ;;; N.B. Quietly retain all unknown slot options (rather than signaling an
  533. ;;; error), so that it's easy to add new ones.
  534.  
  535. (defun make-direct-slot-definition
  536.        (&rest properties
  537.         &key name (initargs ()) (initform nil) (initfunction nil)
  538.              (readers ()) (writers ()) (allocation :instance)
  539.         &allow-other-keys)
  540.   (let ((slot (copy-list properties))) ; Don't want to side effect &rest list
  541.     (setf (getf* slot ':name) name)
  542.     (setf (getf* slot ':initargs) initargs)
  543.     (setf (getf* slot ':initform) initform)
  544.     (setf (getf* slot ':initfunction) initfunction)
  545.     (setf (getf* slot ':readers) readers)
  546.     (setf (getf* slot ':writers) writers)
  547.     (setf (getf* slot ':allocation) allocation)
  548.     slot))
  549.  
  550. (defun make-effective-slot-definition
  551.        (&rest properties
  552.         &key name (initargs ()) (initform nil) (initfunction nil)
  553.              (allocation :instance)
  554.         &allow-other-keys)
  555.   (let ((slot (copy-list properties)))  ; Don't want to side effect &rest list
  556.     (setf (getf* slot ':name) name)
  557.     (setf (getf* slot ':initargs) initargs)
  558.     (setf (getf* slot ':initform) initform)
  559.     (setf (getf* slot ':initfunction) initfunction)
  560.     (setf (getf* slot ':allocation) allocation)
  561.     slot))
  562.  
  563. (defun slot-definition-name (slot)
  564.   (getf slot ':name))
  565. (defun (setf slot-definition-name) (new-value slot)
  566.   (setf (getf* slot ':name) new-value))
  567.  
  568. (defun slot-definition-initfunction (slot)
  569.   (getf slot ':initfunction))
  570. (defun (setf slot-definition-initfunction) (new-value slot)
  571.   (setf (getf* slot ':initfunction) new-value))
  572.  
  573. (defun slot-definition-initform (slot)
  574.   (getf slot ':initform))
  575. (defun (setf slot-definition-initform) (new-value slot)
  576.   (setf (getf* slot ':initform) new-value))
  577.  
  578. (defun slot-definition-initargs (slot)
  579.   (getf slot ':initargs))
  580. (defun (setf slot-definition-initargs) (new-value slot)
  581.   (setf (getf* slot ':initargs) new-value))
  582.  
  583. (defun slot-definition-readers (slot)
  584.   (getf slot ':readers))
  585. (defun (setf slot-definition-readers) (new-value slot)
  586.   (setf (getf* slot ':readers) new-value))
  587.  
  588. (defun slot-definition-writers (slot)
  589.   (getf slot ':writers))
  590. (defun (setf slot-definition-writers) (new-value slot)
  591.   (setf (getf* slot ':writers) new-value))
  592.  
  593. (defun slot-definition-allocation (slot)
  594.   (getf slot ':allocation))
  595. (defun (setf slot-definition-allocation) (new-value slot)
  596.   (setf (getf* slot ':allocation) new-value))
  597.  
  598. ;;; finalize-inheritance
  599.  
  600. (defun std-finalize-inheritance (class) 
  601.   (setf (class-precedence-list class)
  602.         (funcall (if (eq (class-of class) the-class-standard-class)
  603.                      #'std-compute-class-precedence-list
  604.                      #'compute-class-precedence-list)
  605.                  class))
  606.   (setf (class-slots class)
  607.         (funcall (if (eq (class-of class) the-class-standard-class)
  608.                      #'std-compute-slots
  609.                      #'compute-slots)
  610.                  class))
  611.   (values))
  612.  
  613. ;;; Class precedence lists
  614.  
  615. (defun std-compute-class-precedence-list (class)
  616.   (let ((classes-to-order (collect-superclasses* class)))
  617.     (topological-sort classes-to-order
  618.                       (remove-duplicates
  619.                         (mapappend #'local-precedence-ordering
  620.                                    classes-to-order))
  621.                       #'std-tie-breaker-rule)))
  622.  
  623. ;;; topological-sort implements the standard algorithm for topologically
  624. ;;; sorting an arbitrary set of elements while honoring the precedence
  625. ;;; constraints given by a set of (X,Y) pairs that indicate that element
  626. ;;; X must precede element Y.  The tie-breaker procedure is called when it
  627. ;;; is necessary to choose from multiple minimal elements; both a list of 
  628. ;;; candidates and the ordering so far are provided as arguments.
  629.  
  630. (defun topological-sort (elements constraints tie-breaker)
  631.   (let ((remaining-constraints constraints)
  632.         (remaining-elements elements)
  633.         (result ())) 
  634.     (loop
  635.      (let ((minimal-elements 
  636.             (remove-if
  637.              #'(lambda (class)
  638.                  (member class remaining-constraints
  639.                          :key #'cadr))
  640.              remaining-elements)))
  641.        (when (null minimal-elements)
  642.              (if (null remaining-elements)
  643.                  (return-from topological-sort result)
  644.                (error "Inconsistent precedence graph.")))
  645.        (let ((choice (if (null (cdr minimal-elements))
  646.                          (car minimal-elements)
  647.                        (funcall tie-breaker
  648.                                 minimal-elements
  649.                                 result))))
  650.          (setq result (append result (list choice)))
  651.          (setq remaining-elements
  652.                (remove choice remaining-elements))
  653.          (setq remaining-constraints
  654.                (remove choice
  655.                        remaining-constraints
  656.                        :test #'member)))))))
  657.  
  658. ;;; In the event of a tie while topologically sorting class precedence lists,
  659. ;;; the CLOS Specification says to "select the one that has a direct subclass
  660. ;;; rightmost in the class precedence list computed so far."  The same result
  661. ;;; is obtained by inspecting the partially constructed class precedence list
  662. ;;; from right to left, looking for the first minimal element to show up among
  663. ;;; the direct superclasses of the class precedence list constituent.  
  664. ;;; (There's a lemma that shows that this rule yields a unique result.)
  665.  
  666. (defun std-tie-breaker-rule (minimal-elements cpl-so-far)
  667.   (dolist (cpl-constituent (reverse cpl-so-far))
  668.     (let* ((supers (class-direct-superclasses cpl-constituent))
  669.            (common (intersection minimal-elements supers)))
  670.       (when (not (null common))
  671.         (return-from std-tie-breaker-rule (car common))))))
  672.  
  673. ;;; This version of collect-superclasses* isn't bothered by cycles in the class
  674. ;;; hierarchy, which sometimes happen by accident.
  675.  
  676. (defun collect-superclasses* (class)
  677.   (labels ((all-superclasses-loop (seen superclasses)
  678.               (let ((to-be-processed
  679.                        (set-difference superclasses seen)))
  680.                 (if (null to-be-processed)
  681.                     superclasses
  682.                     (let ((class-to-process
  683.                              (car to-be-processed)))
  684.                       (all-superclasses-loop
  685.                         (cons class-to-process seen)
  686.                         (union (class-direct-superclasses
  687.                                  class-to-process)
  688.                                superclasses)))))))
  689.     (all-superclasses-loop () (list class))))
  690.  
  691. ;;; The local precedence ordering of a class C with direct superclasses C_1,
  692. ;;; C_2, ..., C_n is the set ((C C_1) (C_1 C_2) ...(C_n-1 C_n)).
  693.  
  694. (defun local-precedence-ordering (class)
  695.   (mapcar #'list 
  696.           (cons class
  697.                 (butlast (class-direct-superclasses class)))
  698.           (class-direct-superclasses class)))
  699.  
  700. ;;; Slot inheritance
  701.  
  702. (defun std-compute-slots (class)
  703.   (let* ((all-slots (mapappend #'class-direct-slots
  704.                                (class-precedence-list class)))
  705.          (all-names (remove-duplicates 
  706.                       (mapcar #'slot-definition-name all-slots))))
  707.     (mapcar #'(lambda (name)
  708.                 (funcall
  709.                   (if (eq (class-of class) the-class-standard-class)
  710.                       #'std-compute-effective-slot-definition 
  711.                       #'compute-effective-slot-definition)
  712.                   class
  713.                   (remove name all-slots
  714.                           :key #'slot-definition-name
  715.                           :test-not #'eq)))
  716.             all-names)))
  717.  
  718. (defun std-compute-effective-slot-definition (class direct-slots)
  719.   (declare (ignore class))
  720.   (let ((initer (find-if-not #'null direct-slots
  721.                              :key #'slot-definition-initfunction)))
  722.     (make-effective-slot-definition
  723.       :name (slot-definition-name (car direct-slots))
  724.       :initform (if initer
  725.                     (slot-definition-initform initer)
  726.                     nil)
  727.       :initfunction (if initer
  728.                         (slot-definition-initfunction initer)
  729.                         nil)
  730.       :initargs (remove-duplicates 
  731.                   (mapappend #'slot-definition-initargs
  732.                              direct-slots))
  733.       :allocation (slot-definition-allocation (car direct-slots)))))
  734.  
  735. ;;;
  736. ;;; Generic function metaobjects and standard-generic-function
  737. ;;;
  738.  
  739. (defparameter the-defclass-standard-generic-function
  740.  '(defclass standard-generic-function ()
  741.       ((name :initarg :name)      ; :accessor generic-function-name
  742.        (lambda-list               ; :accessor generic-function-lambda-list
  743.           :initarg :lambda-list)          
  744.        (methods :initform ())     ; :accessor generic-function-methods
  745.        (method-class              ; :accessor generic-function-method-class
  746.           :initarg :method-class)
  747.        (discriminating-function)  ; :accessor generic-function-
  748.                                   ;    -discriminating-function
  749.        (classes-to-emf-table      ; :accessor classes-to-emf-table
  750.           :initform (make-hash-table :test #'equal)))))
  751.  
  752. (defvar the-class-standard-gf) ;standard-generic-function's class metaobject
  753.  
  754. (defun generic-function-name (gf)
  755.   (slot-value gf 'name))
  756. (defun (setf generic-function-name) (new-value gf)
  757.   (setf (slot-value gf 'name) new-value))
  758.  
  759. (defun generic-function-lambda-list (gf)
  760.   (slot-value gf 'lambda-list))
  761. (defun (setf generic-function-lambda-list) (new-value gf)
  762.   (setf (slot-value gf 'lambda-list) new-value))
  763.  
  764. (defun generic-function-methods (gf)
  765.   (slot-value gf 'methods))
  766. (defun (setf generic-function-methods) (new-value gf)
  767.   (setf (slot-value gf 'methods) new-value))
  768.  
  769. (defun generic-function-discriminating-function (gf)
  770.   (slot-value gf 'discriminating-function))
  771. (defun (setf generic-function-discriminating-function) (new-value gf)
  772.   (setf (slot-value gf 'discriminating-function) new-value))
  773.  
  774. (defun generic-function-method-class (gf)
  775.   (slot-value gf 'method-class))
  776. (defun (setf generic-function-method-class) (new-value gf)
  777.   (setf (slot-value gf 'method-class) new-value))
  778.  
  779. ;;; Internal accessor for effective method function table
  780.  
  781. (defun classes-to-emf-table (gf)
  782.   (slot-value gf 'classes-to-emf-table))
  783. (defun (setf classes-to-emf-table) (new-value gf)
  784.   (setf (slot-value gf 'classes-to-emf-table) new-value))
  785.  
  786. ;;;
  787. ;;; Method metaobjects and standard-method
  788. ;;;
  789.  
  790. (defparameter the-defclass-standard-method
  791.  '(defclass standard-method ()
  792.    ((lambda-list :initarg :lambda-list)     ; :accessor method-lambda-list
  793.     (qualifiers :initarg :qualifiers)       ; :accessor method-qualifiers
  794.     (specializers :initarg :specializers)   ; :accessor method-specializers
  795.     (body :initarg :body)                   ; :accessor method-body
  796.     (environment :initarg :environment)     ; :accessor method-environment
  797.     (generic-function :initform nil)        ; :accessor method-generic-function
  798.     (function))))                           ; :accessor method-function
  799.  
  800. (defvar the-class-standard-method)    ;standard-method's class metaobject
  801.  
  802. (defun method-lambda-list (method) (slot-value method 'lambda-list))
  803. (defun (setf method-lambda-list) (new-value method)
  804.   (setf (slot-value method 'lambda-list) new-value))
  805.  
  806. (defun method-qualifiers (method) (slot-value method 'qualifiers))
  807. (defun (setf method-qualifiers) (new-value method)
  808.   (setf (slot-value method 'qualifiers) new-value))
  809.  
  810. (defun method-specializers (method) (slot-value method 'specializers))
  811. (defun (setf method-specializers) (new-value method)
  812.   (setf (slot-value method 'specializers) new-value))
  813.  
  814. (defun method-body (method) (slot-value method 'body))
  815. (defun (setf method-body) (new-value method)
  816.   (setf (slot-value method 'body) new-value))
  817.  
  818. (defun method-environment (method) (slot-value method 'environment))
  819. (defun (setf method-environment) (new-value method)
  820.   (setf (slot-value method 'environment) new-value))
  821.  
  822. (defun method-generic-function (method)
  823.   (slot-value method 'generic-function))
  824. (defun (setf method-generic-function) (new-value method)
  825.   (setf (slot-value method 'generic-function) new-value))
  826.  
  827. (defun method-function (method) (slot-value method 'function))
  828. (defun (setf method-function) (new-value method)
  829.   (setf (slot-value method 'function) new-value))
  830.  
  831. ;;; defgeneric
  832.  
  833. (defmacro defgeneric (function-name lambda-list &rest options)
  834.   `(ensure-generic-function
  835.      ',function-name 
  836.      :lambda-list ',lambda-list
  837.      ,@(canonicalize-defgeneric-options options)))
  838.  
  839. (defun canonicalize-defgeneric-options (options)
  840.   (mapappend #'canonicalize-defgeneric-option options))
  841.  
  842. (defun canonicalize-defgeneric-option (option)
  843.   (case (car option)
  844.     (:generic-function-class
  845.       (list ':generic-function-class
  846.             `(find-class ',(cadr option))))
  847.     (:method-class
  848.       (list ':method-class
  849.             `(find-class ',(cadr option))))
  850.     (t (list `',(car option) `',(cadr option)))))
  851.  
  852. ;;; find-generic-function looks up a generic function by name.  It's an
  853. ;;; artifact of the fact that our generic function metaobjects can't legally
  854. ;;; be stored a symbol's function value. 
  855.  
  856. (let ((generic-function-table (make-hash-table :test #'equal)))
  857.  
  858.   (defun find-generic-function (symbol &optional (errorp t))
  859.     (let ((gf (gethash symbol generic-function-table nil)))
  860.        (if (and (null gf) errorp)
  861.            (error "No generic function named ~S." symbol)
  862.            gf)))
  863.  
  864.   (defun (setf find-generic-function) (new-value symbol)
  865.     (setf (gethash symbol generic-function-table) new-value))
  866.  
  867.   (defun forget-all-generic-functions ()
  868.     (clrhash generic-function-table)
  869.     (values))
  870.  ) ;end let generic-function-table
  871.  
  872. ;;; ensure-generic-function
  873.  
  874. (defun ensure-generic-function
  875.        (function-name
  876.         &rest all-keys
  877.         &key (generic-function-class the-class-standard-gf)
  878.              (method-class the-class-standard-method)
  879.         &allow-other-keys)
  880.   (if (find-generic-function function-name nil) 
  881.       (find-generic-function function-name)
  882.       (let ((gf (apply (if (eq generic-function-class the-class-standard-gf)
  883.                            #'make-instance-standard-generic-function
  884.                            #'make-instance)
  885.                        generic-function-class
  886.                        :name function-name
  887.                        :method-class method-class
  888.                        all-keys)))
  889.          (setf (find-generic-function function-name) gf)
  890.          gf)))
  891.  
  892. ;;; finalize-generic-function
  893.  
  894. ;;; N.B. Same basic idea as finalize-inheritance.  Takes care of recomputing
  895. ;;; and storing the discriminating function, and clearing the effective method
  896. ;;; function table.
  897.  
  898. (defun finalize-generic-function (gf)
  899.   (setf (generic-function-discriminating-function gf)
  900.         (funcall (if (eq (class-of gf) the-class-standard-gf)
  901.                      #'std-compute-discriminating-function
  902.                      #'compute-discriminating-function)
  903.                  gf))
  904.   (setf (fdefinition (generic-function-name gf))
  905.         (generic-function-discriminating-function gf))
  906.   (clrhash (classes-to-emf-table gf))
  907.   (values))
  908.  
  909. ;;; make-instance-standard-generic-function creates and initializes an
  910. ;;; instance of standard-generic-function without falling into method lookup.
  911. ;;; However, it cannot be called until standard-generic-function exists.
  912.  
  913. (defun make-instance-standard-generic-function
  914.        (generic-function-class &key name lambda-list method-class)
  915.   (declare (ignore generic-function-class))
  916.   (let ((gf (std-allocate-instance the-class-standard-gf)))
  917.     (setf (generic-function-name gf) name)
  918.     (setf (generic-function-lambda-list gf) lambda-list)
  919.     (setf (generic-function-methods gf) ()) 
  920.     (setf (generic-function-method-class gf) method-class) 
  921.     (setf (classes-to-emf-table gf) (make-hash-table :test #'equal))
  922.     (finalize-generic-function gf)
  923.     gf))
  924.  
  925. ;;; defmethod
  926.  
  927. (defmacro defmethod (&rest args)
  928.   (multiple-value-bind (function-name qualifiers
  929.                         lambda-list specializers body)
  930.         (parse-defmethod args)
  931.     `(ensure-method (find-generic-function ',function-name)
  932.        :lambda-list ',lambda-list
  933.        :qualifiers ',qualifiers
  934.        :specializers ,(canonicalize-specializers specializers) 
  935.        :body ',body
  936.        :environment (top-level-environment))))
  937.  
  938. (defun canonicalize-specializers (specializers)
  939.   `(list ,@(mapcar #'canonicalize-specializer specializers)))
  940.  
  941. (defun canonicalize-specializer (specializer)
  942.   `(find-class ',specializer))
  943.  
  944. (defun parse-defmethod (args)
  945.   (let ((fn-spec (car args))
  946.         (qualifiers ())
  947.         (specialized-lambda-list nil)
  948.         (body ())
  949.         (parse-state :qualifiers))
  950.     (dolist (arg (cdr args))
  951.        (ecase parse-state
  952.          (:qualifiers
  953.            (if (and (atom arg) (not (null arg)))
  954.                (push-on-end arg qualifiers)
  955.                (progn (setq specialized-lambda-list arg)
  956.                       (setq parse-state :body))))
  957.          (:body (push-on-end arg body))))
  958.     (values fn-spec 
  959.             qualifiers
  960.             (extract-lambda-list specialized-lambda-list)
  961.             (extract-specializers specialized-lambda-list)
  962.             (list* 'block
  963.                    (if (consp fn-spec)
  964.                        (cadr fn-spec)
  965.                        fn-spec)
  966.                    body))))
  967.  
  968. ;;; Several tedious functions for analyzing lambda lists
  969.  
  970. (defun required-portion (gf args)
  971.   (let ((number-required (length (gf-required-arglist gf))))
  972.     (when (< (length args) number-required)
  973.       (error "Too few arguments to generic function ~S." gf))
  974.     (subseq args 0 number-required)))
  975.  
  976. (defun gf-required-arglist (gf)
  977.   (let ((plist
  978.           (analyze-lambda-list 
  979.             (generic-function-lambda-list gf))))
  980.     (getf plist ':required-args)))
  981.  
  982. (defun extract-lambda-list (specialized-lambda-list)
  983.   (let* ((plist (analyze-lambda-list specialized-lambda-list))
  984.          (requireds (getf plist ':required-names))
  985.          (rv (getf plist ':rest-var))
  986.          (ks (getf plist ':key-args))
  987.          (aok (getf plist ':allow-other-keys))
  988.          (opts (getf plist ':optional-args))
  989.          (auxs (getf plist ':auxiliary-args)))
  990.     `(,@requireds 
  991.       ,@(if rv `(&rest ,rv) ())
  992.       ,@(if (or ks aok) `(&key ,@ks) ())
  993.       ,@(if aok '(&allow-other-keys) ())
  994.       ,@(if opts `(&optional ,@opts) ())
  995.       ,@(if auxs `(&aux ,@auxs) ()))))
  996.  
  997. (defun extract-specializers (specialized-lambda-list)
  998.   (let ((plist (analyze-lambda-list specialized-lambda-list)))
  999.     (getf plist ':specializers)))
  1000.  
  1001. (defun analyze-lambda-list (lambda-list)
  1002.   (labels ((make-keyword (symbol)
  1003.               (intern (symbol-name symbol)
  1004.                       (find-package 'keyword)))
  1005.            (get-keyword-from-arg (arg)
  1006.               (if (listp arg)
  1007.                   (if (listp (car arg))
  1008.                       (caar arg)
  1009.                       (make-keyword (car arg)))
  1010.                   (make-keyword arg))))
  1011.     (let ((keys ())           ; Just the keywords
  1012.           (key-args ())       ; Keywords argument specs
  1013.           (required-names ()) ; Just the variable names
  1014.           (required-args ())  ; Variable names & specializers
  1015.           (specializers ())   ; Just the specializers
  1016.           (rest-var nil)
  1017.           (optionals ())
  1018.           (auxs ())
  1019.           (allow-other-keys nil)
  1020.           (state :parsing-required))
  1021.       (dolist (arg lambda-list)
  1022.         (if (member arg lambda-list-keywords)
  1023.           (ecase arg
  1024.             (&optional
  1025.               (setq state :parsing-optional))
  1026.             (&rest
  1027.               (setq state :parsing-rest))
  1028.             (&key
  1029.               (setq state :parsing-key))
  1030.             (&allow-other-keys
  1031.               (setq allow-other-keys 't))
  1032.             (&aux
  1033.               (setq state :parsing-aux)))
  1034.           (case state
  1035.             (:parsing-required 
  1036.              (push-on-end arg required-args)
  1037.              (if (listp arg)
  1038.                  (progn (push-on-end (car arg) required-names)
  1039.                         (push-on-end (cadr arg) specializers))
  1040.                  (progn (push-on-end arg required-names)
  1041.                         (push-on-end 't specializers))))
  1042.             (:parsing-optional (push-on-end arg optionals))
  1043.             (:parsing-rest (setq rest-var arg))
  1044.             (:parsing-key
  1045.              (push-on-end (get-keyword-from-arg arg) keys)
  1046.              (push-on-end arg key-args))
  1047.             (:parsing-aux (push-on-end arg auxs)))))
  1048.       (list  :required-names required-names
  1049.              :required-args required-args
  1050.              :specializers specializers
  1051.              :rest-var rest-var
  1052.              :keywords keys
  1053.              :key-args key-args
  1054.              :auxiliary-args auxs
  1055.              :optional-args optionals
  1056.              :allow-other-keys allow-other-keys))))
  1057.  
  1058. ;;; ensure method
  1059.  
  1060. (defun ensure-method (gf &rest all-keys)
  1061.   (let ((new-method
  1062.            (apply
  1063.               (if (eq (generic-function-method-class gf)
  1064.                       the-class-standard-method)
  1065.                   #'make-instance-standard-method 
  1066.                   #'make-instance)
  1067.               (generic-function-method-class gf)
  1068.               all-keys)))
  1069.     (add-method gf new-method)
  1070.     new-method))
  1071.  
  1072. ;;; make-instance-standard-method creates and initializes an instance of
  1073. ;;; standard-method without falling into method lookup.  However, it cannot
  1074. ;;; be called until standard-method exists.
  1075.  
  1076. (defun make-instance-standard-method (method-class 
  1077.                                       &key lambda-list qualifiers 
  1078.                                            specializers body environment)
  1079.   (declare (ignore method-class))
  1080.   (let ((method (std-allocate-instance the-class-standard-method)))
  1081.     (setf (method-lambda-list method) lambda-list)
  1082.     (setf (method-qualifiers method) qualifiers)
  1083.     (setf (method-specializers method) specializers)
  1084.     (setf (method-body method) body)
  1085.     (setf (method-environment method) environment)
  1086.     (setf (method-generic-function method) nil)
  1087.     (setf (method-function method) 
  1088.           (std-compute-method-function method))
  1089.     method))
  1090.  
  1091. ;;; add-method
  1092.  
  1093. ;;; N.B. This version first removes any existing method on the generic function
  1094. ;;; with the same qualifiers and specializers.  It's a pain to develop
  1095. ;;; programs without this feature of full CLOS.
  1096.  
  1097. (defun add-method (gf method)
  1098.   (let ((old-method
  1099.            (find-method gf (method-qualifiers method)
  1100.                            (method-specializers method) nil)))
  1101.     (when old-method (remove-method gf old-method)))
  1102.   (setf (method-generic-function method) gf)
  1103.   (push method (generic-function-methods gf))
  1104.   (dolist (specializer (method-specializers method))
  1105.     (pushnew method (class-direct-methods specializer)))
  1106.   (finalize-generic-function gf)
  1107.   method)
  1108.  
  1109. (defun remove-method (gf method)
  1110.   (setf (generic-function-methods gf)
  1111.         (remove method (generic-function-methods gf)))
  1112.   (setf (method-generic-function method) nil)
  1113.   (dolist (class (method-specializers method))
  1114.     (setf (class-direct-methods class)
  1115.           (remove method (class-direct-methods class))))
  1116.   (finalize-generic-function gf)
  1117.   method)
  1118.  
  1119. (defun find-method (gf qualifiers specializers
  1120.                     &optional (errorp t))
  1121.   (let ((method
  1122.           (find-if #'(lambda (method)
  1123.                        (and (equal qualifiers
  1124.                                    (method-qualifiers method))
  1125.                             (equal specializers
  1126.                                    (method-specializers method))))
  1127.                    (generic-function-methods gf))))
  1128.       (if (and (null method) errorp)
  1129.           (error "No such method for ~S." (generic-function-name gf))
  1130.           method)))
  1131.  
  1132. ;;; Reader and write methods
  1133.  
  1134. (defun add-reader-method (class fn-name slot-name)
  1135.   (ensure-method
  1136.     (ensure-generic-function fn-name :lambda-list '(object))
  1137.     :lambda-list '(object)
  1138.     :qualifiers ()
  1139.     :specializers (list class)
  1140.     :body `(slot-value object ',slot-name)
  1141.     :environment (top-level-environment))
  1142.   (values))
  1143.  
  1144. (defun add-writer-method (class fn-name slot-name)
  1145.   (ensure-method
  1146.     (ensure-generic-function 
  1147.       fn-name :lambda-list '(new-value object))
  1148.     :lambda-list '(new-value object)
  1149.     :qualifiers ()
  1150.     :specializers (list (find-class 't) class)
  1151.     :body `(setf (slot-value object ',slot-name)
  1152.                  new-value)
  1153.     :environment (top-level-environment))
  1154.   (values))
  1155.  
  1156. ;;;
  1157. ;;; Generic function invocation
  1158. ;;;
  1159.  
  1160. ;;; apply-generic-function
  1161.  
  1162. (defun apply-generic-function (gf args)
  1163.   (apply (generic-function-discriminating-function gf) args))
  1164.  
  1165. ;;; compute-discriminating-function
  1166.  
  1167. (defun std-compute-discriminating-function (gf)
  1168.   #'(lambda (&rest args)
  1169.       (let* ((classes (mapcar #'class-of 
  1170.                               (required-portion gf args)))
  1171.              (emfun (gethash classes (classes-to-emf-table gf) nil)))
  1172.         (if emfun
  1173.             (funcall emfun args)
  1174.             (slow-method-lookup gf args classes)))))
  1175.  
  1176. (defun slow-method-lookup (gf args classes)
  1177.   (let* ((applicable-methods
  1178.            (compute-applicable-methods-using-classes gf classes))
  1179.          (emfun
  1180.            (funcall
  1181.              (if (eq (class-of gf) the-class-standard-gf)
  1182.                  #'std-compute-effective-method-function
  1183.                  #'compute-effective-method-function)
  1184.              gf applicable-methods)))
  1185.     (setf (gethash classes (classes-to-emf-table gf)) emfun)
  1186.     (funcall emfun args)))
  1187.  
  1188. ;;; compute-applicable-methods-using-classes
  1189.  
  1190. (defun compute-applicable-methods-using-classes
  1191.        (gf required-classes)
  1192.   (sort 
  1193.     (copy-list
  1194.       (remove-if-not #'(lambda (method)
  1195.                          (every #'subclassp
  1196.                                 required-classes
  1197.                                 (method-specializers method)))
  1198.                      (generic-function-methods gf)))
  1199.     #'(lambda (m1 m2) 
  1200.         (funcall
  1201.           (if (eq (class-of gf) the-class-standard-gf)
  1202.               #'std-method-more-specific-p
  1203.               #'method-more-specific-p)
  1204.           gf m1 m2 required-classes))))
  1205.  
  1206. ;;; method-more-specific-p
  1207.  
  1208. (defun std-method-more-specific-p (gf method1 method2 required-classes)
  1209.   (declare (ignore gf))
  1210.   (mapc #'(lambda (spec1 spec2 arg-class)
  1211.             (unless (eq spec1 spec2)
  1212.               (return-from std-method-more-specific-p
  1213.                  (sub-specializer-p spec1 spec2 arg-class))))
  1214.         (method-specializers method1)
  1215.         (method-specializers method2)
  1216.         required-classes)
  1217.   nil)
  1218.  
  1219. ;;; apply-methods and compute-effective-method-function
  1220.  
  1221. (defun apply-methods (gf args methods)
  1222.   (funcall (compute-effective-method-function gf methods)
  1223.            args))
  1224.  
  1225. (defun primary-method-p (method)
  1226.   (null (method-qualifiers method)))
  1227. (defun before-method-p (method)
  1228.   (equal '(:before) (method-qualifiers method)))
  1229. (defun after-method-p (method)
  1230.   (equal '(:after) (method-qualifiers method)))
  1231. (defun around-method-p (method)
  1232.   (equal '(:around) (method-qualifiers method)))
  1233.  
  1234. (defun std-compute-effective-method-function (gf methods)
  1235.   (let ((primaries (remove-if-not #'primary-method-p methods))
  1236.         (around (find-if #'around-method-p methods)))
  1237.     (when (null primaries)
  1238.       (error "No primary methods for the~@
  1239.              generic function ~S." gf))
  1240.     (if around
  1241.         (let ((next-emfun
  1242.                 (funcall
  1243.                    (if (eq (class-of gf) the-class-standard-gf)
  1244.                        #'std-compute-effective-method-function
  1245.                        #'compute-effective-method-function)
  1246.                    gf (remove around methods))))
  1247.           #'(lambda (args)
  1248.               (funcall (method-function around) args next-emfun)))
  1249.         (let ((next-emfun (compute-primary-emfun (cdr primaries)))
  1250.               (befores (remove-if-not #'before-method-p methods))
  1251.               (reverse-afters
  1252.                 (reverse (remove-if-not #'after-method-p methods))))
  1253.           #'(lambda (args)        
  1254.               (dolist (before befores)
  1255.                 (funcall (method-function before) args nil))
  1256.               (multiple-value-prog1
  1257.                 (funcall (method-function (car primaries)) args next-emfun)
  1258.                 (dolist (after reverse-afters)
  1259.                   (funcall (method-function after) args nil))))))))
  1260.  
  1261. ;;; compute an effective method function from a list of primary methods:
  1262.  
  1263. (defun compute-primary-emfun (methods)
  1264.   (if (null methods)
  1265.       nil
  1266.       (let ((next-emfun (compute-primary-emfun (cdr methods))))               
  1267.         #'(lambda (args)
  1268.             (funcall (method-function (car methods)) args next-emfun)))))
  1269.  
  1270. ;;; apply-method and compute-method-function
  1271.  
  1272. (defun apply-method (method args next-methods)
  1273.   (funcall (method-function method)
  1274.            args
  1275.            (if (null next-methods)
  1276.                nil
  1277.                (compute-effective-method-function
  1278.                  (method-generic-function method) next-methods))))
  1279.  
  1280. (defun std-compute-method-function (method)
  1281.   (let ((form (method-body method))
  1282.         (lambda-list (method-lambda-list method)))
  1283.     (compile-in-lexical-environment (method-environment method)
  1284.       `(lambda (args next-emfun)
  1285.          (flet ((call-next-method (&rest cnm-args)
  1286.                   (if (null next-emfun)
  1287.                       (error "No next method for the~@
  1288.                               generic function ~S." 
  1289.                              (method-generic-function ',method))
  1290.                       (funcall next-emfun (or cnm-args args))))
  1291.                 (next-method-p ()
  1292.                   (not (null next-emfun))))
  1293.             (apply #'(lambda ,(kludge-arglist lambda-list)
  1294.                        ,form)
  1295.                    args))))))
  1296.  
  1297. ;;; N.B. The function kludge-arglist is used to pave over the differences
  1298. ;;; between argument keyword compatibility for regular functions versus 
  1299. ;;; generic functions.
  1300.  
  1301. (defun kludge-arglist (lambda-list)
  1302.   (if (and (member '&key lambda-list)
  1303.            (not (member '&allow-other-keys lambda-list)))
  1304.       (append lambda-list '(&allow-other-keys))
  1305.       (if (and (not (member '&rest lambda-list))
  1306.                (not (member '&key lambda-list)))
  1307.           (append lambda-list '(&key &allow-other-keys))
  1308.           lambda-list)))
  1309.  
  1310. ;;; Run-time environment hacking (Common Lisp ain't got 'em).
  1311.  
  1312. (defun top-level-environment ()
  1313.   nil) ; Bogus top level lexical environment
  1314.  
  1315. (defvar compile-methods nil)      ; by default, run everything interpreted
  1316.  
  1317. (defun compile-in-lexical-environment (env lambda-expr)
  1318.   (declare (ignore env))
  1319.   (if compile-methods
  1320.       (compile nil lambda-expr)
  1321.       (eval `(function ,lambda-expr))))
  1322.  
  1323. ;;;
  1324. ;;; Bootstrap
  1325. ;;;
  1326.  
  1327. (progn  ; Extends to end-of-file (to avoid printing intermediate results).
  1328. ;;(format t "Beginning to bootstrap Closette...")
  1329. (forget-all-classes)
  1330. (forget-all-generic-functions)
  1331. ;; How to create the class hierarchy in 10 easy steps:
  1332. ;; 1. Figure out standard-class's slots.
  1333. (setq the-slots-of-standard-class
  1334.       (mapcar #'(lambda (slotd)
  1335.                   (make-effective-slot-definition
  1336.                     :name (car slotd)
  1337.                     :initargs
  1338.                       (let ((a (getf (cdr slotd) ':initarg)))
  1339.                         (if a (list a) ()))
  1340.                     :initform (getf (cdr slotd) ':initform)
  1341.                     :initfunction
  1342.                       (let ((a (getf (cdr slotd) ':initform)))
  1343.                         (if a #'(lambda () (eval a)) nil))
  1344.                     :allocation ':instance))
  1345.               (nth 3 the-defclass-standard-class)))
  1346. ;; 2. Create the standard-class metaobject by hand.
  1347. (setq the-class-standard-class
  1348.       (allocate-std-instance
  1349.          'tba
  1350.          (make-array (length the-slots-of-standard-class)
  1351.                      :initial-element secret-unbound-value)))
  1352. ;; 3. Install standard-class's (circular) class-of link. 
  1353. (setf (std-instance-class the-class-standard-class) 
  1354.       the-class-standard-class)
  1355. ;; (It's now okay to use class-... accessor).
  1356. ;; 4. Fill in standard-class's class-slots.
  1357. (setf (class-slots the-class-standard-class) the-slots-of-standard-class)
  1358. ;; (Skeleton built; it's now okay to call make-instance-standard-class.)
  1359. ;; 5. Hand build the class t so that it has no direct superclasses.
  1360. (setf (find-class 't) 
  1361.   (let ((class (std-allocate-instance the-class-standard-class)))
  1362.     (setf (class-name class) 't)
  1363.     (setf (class-direct-subclasses class) ())
  1364.     (setf (class-direct-superclasses class) ())
  1365.     (setf (class-direct-methods class) ())
  1366.     (setf (class-direct-slots class) ())
  1367.     (setf (class-precedence-list class) (list class))
  1368.     (setf (class-slots class) ())
  1369.     class))
  1370. ;; (It's now okay to define subclasses of t.)
  1371. ;; 6. Create the other superclass of standard-class (i.e., standard-object).
  1372. (defclass standard-object (t) ())
  1373. ;; 7. Define the full-blown version of standard-class.
  1374. (setq the-class-standard-class (eval the-defclass-standard-class))
  1375. ;; 8. Replace all (3) existing pointers to the skeleton with real one.
  1376. (setf (std-instance-class (find-class 't)) 
  1377.       the-class-standard-class)
  1378. (setf (std-instance-class (find-class 'standard-object)) 
  1379.       the-class-standard-class)
  1380. (setf (std-instance-class the-class-standard-class) 
  1381.       the-class-standard-class)
  1382. ;; (Clear sailing from here on in).
  1383. ;; 9. Define the other built-in classes.
  1384. (defclass symbol (t) ())
  1385. (defclass sequence (t) ())
  1386. (defclass array (t) ())
  1387. (defclass number (t) ())
  1388. (defclass character (t) ())
  1389. (defclass function (t) ())
  1390. (defclass hash-table (t) ())
  1391. (defclass package (t) ())
  1392. (defclass pathname (t) ())
  1393. (defclass readtable (t) ())
  1394. (defclass stream (t) ())
  1395. (defclass list (sequence) ())
  1396. (defclass null (symbol list) ())
  1397. (defclass cons (list) ())
  1398. (defclass vector (array sequence) ())
  1399. (defclass bit-vector (vector) ())
  1400. (defclass string (vector) ())
  1401. (defclass complex (number) ())
  1402. (defclass integer (number) ())
  1403. (defclass float (number) ())
  1404. ;; 10. Define the other standard metaobject classes.
  1405. (setq the-class-standard-gf (eval the-defclass-standard-generic-function))
  1406. (setq the-class-standard-method (eval the-defclass-standard-method))
  1407. ;; Voila! The class hierarchy is in place.
  1408. ;;(format t "Class hierarchy created.")
  1409. ;; (It's now okay to define generic functions and methods.)
  1410.  
  1411. (defgeneric print-object (instance stream))
  1412. (defmethod print-object ((instance standard-object) stream)
  1413.   (print-unreadable-object (instance stream :identity t)
  1414.      (format stream "~:(~S~)"
  1415.                     (class-name (class-of instance))))
  1416.   instance)
  1417.  
  1418. ;;; Slot access
  1419.  
  1420. (defgeneric slot-value-using-class (class instance slot-name))
  1421. (defmethod slot-value-using-class
  1422.            ((class standard-class) instance slot-name)
  1423.   (std-slot-value instance slot-name))
  1424.  
  1425. (defgeneric (setf slot-value-using-class) (new-value class instance slot-name))
  1426. (defmethod (setf slot-value-using-class)
  1427.            (new-value (class standard-class) instance slot-name)
  1428.   (setf (std-slot-value instance slot-name) new-value))
  1429. ;;; N.B. To avoid making a forward reference to a (setf xxx) generic function:
  1430. (defun setf-slot-value-using-class (new-value class object slot-name)
  1431.   (setf (slot-value-using-class class object slot-name) new-value))
  1432.  
  1433. (defgeneric slot-exists-p-using-class (class instance slot-name))
  1434. (defmethod slot-exists-p-using-class
  1435.            ((class standard-class) instance slot-name)
  1436.   (std-slot-exists-p instance slot-name))
  1437.  
  1438. (defgeneric slot-boundp-using-class (class instance slot-name))
  1439. (defmethod slot-boundp-using-class
  1440.            ((class standard-class) instance slot-name)
  1441.   (std-slot-boundp instance slot-name))
  1442.  
  1443. (defgeneric slot-makunbound-using-class (class instance slot-name))
  1444. (defmethod slot-makunbound-using-class
  1445.            ((class standard-class) instance slot-name)
  1446.   (std-slot-makunbound instance slot-name))
  1447.  
  1448. ;;; Instance creation and initialization
  1449.  
  1450. (defgeneric allocate-instance (class))
  1451. (defmethod allocate-instance ((class standard-class))
  1452.   (std-allocate-instance class))
  1453.  
  1454. (defgeneric make-instance (class &key))
  1455. (defmethod make-instance ((class standard-class) &rest initargs)
  1456.   (let ((instance (allocate-instance class)))
  1457.     (apply #'initialize-instance instance initargs)
  1458.     instance))
  1459. (defmethod make-instance ((class symbol) &rest initargs)
  1460.   (apply #'make-instance (find-class class) initargs))
  1461.  
  1462. (defgeneric initialize-instance (instance &key))
  1463. (defmethod initialize-instance ((instance standard-object) &rest initargs)
  1464.   (apply #'shared-initialize instance t initargs))
  1465.  
  1466. (defgeneric reinitialize-instance (instance &key))
  1467. (defmethod reinitialize-instance
  1468.            ((instance standard-object) &rest initargs)
  1469.   (apply #'shared-initialize instance () initargs))
  1470.  
  1471. (defgeneric shared-initialize (instance slot-names &key))
  1472. (defmethod shared-initialize ((instance standard-object) 
  1473.                               slot-names &rest all-keys)
  1474.   (dolist (slot (class-slots (class-of instance)))
  1475.     (let ((slot-name (slot-definition-name slot)))
  1476.       (multiple-value-bind (init-key init-value foundp)
  1477.             (get-properties
  1478.               all-keys (slot-definition-initargs slot))
  1479.          (declare (ignore init-key))
  1480.          (if foundp
  1481.              (setf (slot-value instance slot-name) init-value)
  1482.              (when (and (not (slot-boundp instance slot-name))
  1483.                         (not (null (slot-definition-initfunction slot)))
  1484.                         (or (eq slot-names t)
  1485.                             (member slot-name slot-names)))
  1486.                (setf (slot-value instance slot-name)
  1487.                      (funcall (slot-definition-initfunction slot))))))))
  1488.   instance)
  1489.  
  1490. ;;; change-class
  1491.  
  1492. (defgeneric change-class (instance new-class &key))
  1493. (defmethod change-class
  1494.            ((old-instance standard-object)
  1495.             (new-class standard-class)
  1496.             &rest initargs)
  1497.   (let ((new-instance (allocate-instance new-class)))
  1498.     (dolist (slot-name (mapcar #'slot-definition-name
  1499.                                (class-slots new-class)))
  1500.       (when (and (slot-exists-p old-instance slot-name)
  1501.                  (slot-boundp old-instance slot-name))
  1502.         (setf (slot-value new-instance slot-name) 
  1503.               (slot-value old-instance slot-name))))
  1504.     (rotatef (std-instance-slots new-instance) 
  1505.              (std-instance-slots old-instance))
  1506.     (rotatef (std-instance-class new-instance) 
  1507.              (std-instance-class old-instance))
  1508.     (apply #'update-instance-for-different-class
  1509.            new-instance old-instance initargs)
  1510.     old-instance))
  1511.  
  1512. (defmethod change-class
  1513.            ((instance standard-object) (new-class symbol) &rest initargs)
  1514.   (apply #'change-class instance (find-class new-class) initargs))
  1515.  
  1516. (defgeneric update-instance-for-different-class (old new &key))
  1517. (defmethod update-instance-for-different-class 
  1518.            ((old standard-object) (new standard-object) &rest initargs)
  1519.   (let ((added-slots 
  1520.           (remove-if #'(lambda (slot-name)
  1521.                          (slot-exists-p old slot-name))
  1522.                      (mapcar #'slot-definition-name
  1523.                              (class-slots (class-of new))))))
  1524.     (apply #'shared-initialize new added-slots initargs)))
  1525.  
  1526. ;;;
  1527. ;;;  Methods having to do with class metaobjects.
  1528. ;;;
  1529.  
  1530. (defmethod print-object ((class standard-class) stream)
  1531.   (print-unreadable-object (class stream :identity t)
  1532.     (format stream "~:(~S~) ~S"
  1533.             (class-name (class-of class))
  1534.             (class-name class)))
  1535.   class)
  1536.  
  1537. (defmethod initialize-instance :after ((class standard-class) &rest args)
  1538.   (apply #'std-after-initialization-for-classes class args))
  1539.  
  1540. ;;; Finalize inheritance
  1541.  
  1542. (defgeneric finalize-inheritance (class))
  1543. (defmethod finalize-inheritance ((class standard-class)) 
  1544.   (std-finalize-inheritance class)
  1545.   (values))
  1546.  
  1547. ;;; Class precedence lists
  1548.  
  1549. (defgeneric compute-class-precedence-list (class))
  1550. (defmethod compute-class-precedence-list ((class standard-class))
  1551.   (std-compute-class-precedence-list class))
  1552.  
  1553. ;;; Slot inheritance
  1554.  
  1555. (defgeneric compute-slots (class))
  1556. (defmethod compute-slots ((class standard-class)) 
  1557.   (std-compute-slots class))
  1558.  
  1559. (defgeneric compute-effective-slot-definition (class direct-slots))
  1560. (defmethod compute-effective-slot-definition
  1561.            ((class standard-class) direct-slots)
  1562.   (std-compute-effective-slot-definition class direct-slots))
  1563.  
  1564. ;;;
  1565. ;;; Methods having to do with generic function metaobjects.
  1566. ;;;
  1567.  
  1568. (defmethod print-object ((gf standard-generic-function) stream)
  1569.   (print-unreadable-object (gf stream :identity t)
  1570.      (format stream "~:(~S~) ~S"
  1571.              (class-name (class-of gf)) 
  1572.              (generic-function-name gf)))
  1573.   gf)
  1574.  
  1575. (defmethod initialize-instance :after ((gf standard-generic-function) &key)
  1576.   (finalize-generic-function gf))
  1577.  
  1578. ;;;
  1579. ;;; Methods having to do with method metaobjects.
  1580. ;;;
  1581.  
  1582. (defmethod print-object ((method standard-method) stream)
  1583.   (print-unreadable-object (method stream :identity t)
  1584.      (format stream "~:(~S~) ~S~{ ~S~} ~S"
  1585.                     (class-name (class-of method))
  1586.                     (generic-function-name
  1587.                       (method-generic-function method))
  1588.                     (method-qualifiers method)
  1589.                     (mapcar #'class-name 
  1590.                             (method-specializers method))))
  1591.   method)
  1592.  
  1593. (defmethod initialize-instance :after ((method standard-method) &key)
  1594.   (setf (method-function method) (compute-method-function method)))
  1595.  
  1596. ;;;
  1597. ;;; Methods having to do with generic function invocation.
  1598. ;;;
  1599.  
  1600. (defgeneric compute-discriminating-function (gf))
  1601. (defmethod compute-discriminating-function ((gf standard-generic-function))
  1602.   (std-compute-discriminating-function gf))
  1603.  
  1604. (defgeneric method-more-specific-p (gf method1 method2 required-classes))
  1605. (defmethod method-more-specific-p 
  1606.            ((gf standard-generic-function) method1 method2 required-classes)
  1607.   (std-method-more-specific-p gf method1 method2 required-classes))
  1608.  
  1609. (defgeneric compute-effective-method-function (gf methods))
  1610. (defmethod compute-effective-method-function
  1611.            ((gf standard-generic-function) methods)
  1612.   (std-compute-effective-method-function gf methods))
  1613.  
  1614. (defgeneric compute-method-function (method))
  1615. (defmethod compute-method-function ((method standard-method))
  1616.   (std-compute-method-function method))
  1617.  
  1618. ;;; describe-object is a handy tool for enquiring minds:
  1619.  
  1620. (defgeneric describe-object (object stream))
  1621. (defmethod describe-object ((object standard-object) stream)
  1622.   (format t "A Closette object~
  1623.              ~%Printed representation: ~S~
  1624.              ~%Class: ~S~
  1625.              ~%Structure "
  1626.           object 
  1627.           (class-of object))
  1628.   (dolist (sn (mapcar #'slot-definition-name
  1629.                       (class-slots (class-of object))))
  1630.     (format t "~%    ~S <- ~:[not bound~;~S~]"
  1631.             sn 
  1632.             (slot-boundp object sn)
  1633.             (and (slot-boundp object sn)
  1634.                  (slot-value object sn))))
  1635.   (values))
  1636. (defmethod describe-object ((object t) stream)
  1637.   (lisp:describe object)
  1638.   (values))
  1639.  
  1640. ;;(format t "~%Closette is a Knights of the Lambda Calculus production.")
  1641.  
  1642. (values)) ;end progn
  1643.  
  1644.  
  1645.  
  1646.  
  1647.  
  1648.  
  1649.  
  1650.  
  1651.  
  1652.  
  1653.  
  1654.  
  1655.  
  1656.  
  1657.  
  1658.  
  1659.